<?php

namespace App\Http\Controllers\Auth;

use App\Jobs\SendRetrievePasswordCodeMail;
use App\Models\User;
use App\Http\Controllers\Controller;
use App\Http\Requests\StoreUserRequest;
use App\Http\Controllers\Traits\SocialiteHelper;
use App\Models\UserCode;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Laracasts\Flash\Flash;
use Phphub\Listeners\UserCreatorListener;
use Jrean\UserVerification\Traits\VerifiesUsers;
use Jrean\UserVerification\Facades\UserVerification;
use Jrean\UserVerification\Exceptions\UserNotFoundException;
use Jrean\UserVerification\Exceptions\UserIsVerifiedException;
use Jrean\UserVerification\Exceptions\TokenMismatchException;
use Cache;
use Carbon\Carbon;

class AuthController extends Controller implements UserCreatorListener
{
    const FIND_PASSWD_EMAIL = 'find_passwd_email';
    const FIND_PASSWD_STEP_ONE = 'find_passwd_step_one';
    const FIND_PASSWD_STEP_TWO = 'find_passwd_step_two';

    use VerifiesUsers, SocialiteHelper, AuthenticatesAndRegistersUsers, ThrottlesLogins;

    protected $redirectTo = '/topics';

    /**
     * Create a new authentication controller instance.
     *
     * @return void
     */
    public function __construct(User $userModel)
    {
        $this->middleware('guest', ['except' => ['logout', 'oauth', 'callback', 'getVerification', 'userBanned']]);
    }

    private function loginUser($user)
    {
        if ($user->is_banned == 'yes') {
            return $this->userIsBanned($user);
        }

        return $this->userFound($user);
    }

    public function logout()
    {
        $tm1 = Cache::get('user_online_tm1-'.Auth::user()->id);
        if($tm1)
        {
            //毫秒
            $duration = floor(Carbon::now()->getTimestamp()-$tm1);
            User::where('id', Auth::user()->id)->increment('online_duration', $duration);
            Cache::forget('user_online_tm1-'.Auth::user()->id);
            Cache::forget('user_online_tm2-'.Auth::user()->id);
        }

        Auth::logout();
        Flash::success(lang('Operation succeeded.'));



        return redirect(route('home'));
    }

    public function loginRequired()
    {
        return view('auth.loginrequired');
    }

    public function signin()
    {
        return view('auth.signin');
    }

    public function signup()
    {
        return view('auth.signup');
    }

    public function postRegister(StoreUserRequest $request)
    {
        $userData = $request->only('name', 'email', 'password');
        $userData['register_source'] = 'self';

        return app(\Phphub\Creators\UserCreator::class)->create($this, $userData);
    }

    public function signinStore()
    {
        return view('auth.signin');
    }

    public function adminRequired()
    {
        return view('auth.adminrequired');
    }

    /**
     * Shows a user what their new account will look like.
     */
    public function create()
    {
        if (! Session::has('oauthData')) {
            return redirect()->route('login');
        }

        $oauthData = array_merge(Session::get('oauthData'), Session::get('_old_input', []));

        return view('auth.signupconfirm', compact('oauthData'));
    }


    /**
     * Actually creates the new user account
     *
     * @param StoreUserRequest $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function createNewUser(StoreUserRequest $request)
    {
        if (! Session::has('oauthData')) {
            return redirect()->route('login');
        }
        $oauthUser = array_merge(Session::get('oauthData'), $request->only('name', 'email', 'password'));
        $userData = array_only($oauthUser, array_keys($request->rules()));
        $userData['register_source'] = $oauthUser['driver'];

        return app(\Phphub\Creators\UserCreator::class)->create($this, $userData);
    }

    public function userBanned()
    {
        if (Auth::check() && Auth::user()->is_banned == 'no') {
            return redirect(route('home'));
        }

        return view('auth.userbanned');
    }

    /**
     * ----------------------------------------
     * UserCreatorListener Delegate
     * ----------------------------------------
     */
    public function userValidationError($errors)
    {
        return redirect('/');
    }

    public function userCreated($user)
    {

        Auth::login($user, true);
        Session::forget('oauthData');

        Flash::success(lang('Congratulations and Welcome!'));

        return redirect(route('users.edit', Auth::user()->id));
    }

    /**
     * GithubAuthenticatorListener Delegate
     *
     * @param $driver
     * @param $registerUserData
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function userNotFound($driver, $registerUserData)
    {
        if ($driver == 'github') {
            $oauthData['image_url'] = $registerUserData->user['avatar_url'];
            $oauthData['github_id'] = $registerUserData->user['id'];
            $oauthData['github_url'] = $registerUserData->user['url'];
            $oauthData['github_name'] = $registerUserData->nickname;
            $oauthData['name'] = $registerUserData->user['name'];
            $oauthData['email'] = $registerUserData->user['email'];
        } elseif ($driver == 'wechat') {
            $oauthData['image_url'] = $registerUserData->avatar;
            $oauthData['wechat_openid'] = $registerUserData->id;
            $oauthData['name'] = $registerUserData->nickname;
            $oauthData['email'] = $registerUserData->email;
            $oauthData['wechat_unionid'] = $registerUserData->user['unionid'];
        }
        elseif ($driver == 'qq')
        {
            $oauthData['image_url'] = $registerUserData->avatar;
            $oauthData['qq_openid'] = $registerUserData->id;
            $oauthData['name'] = $registerUserData->nickname;
            $oauthData['email'] = $registerUserData->email;
            $oauthData['qq_unionid'] = $registerUserData->unionid;
        }

        $oauthData['driver'] = $driver;
        Session::put('oauthData', $oauthData);

        return redirect(route('signup'));
    }

    // 数据库有用户信息, 登录用户
    public function userFound($user)
    {
        Auth::login($user, true);
        Session::forget('oauthData');

        Flash::success(lang('Login Successfully.'));

        return redirect(route('users.edit', Auth::user()->id));
    }

    // 用户屏蔽
    public function userIsBanned($user)
    {
        return redirect(route('user-banned'));
    }

    /**
     * Email Validation
     *
     * @param Request $request
     * @param $token
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function getVerification(Request $request, $token)
    {
        $this->validateRequest($request);
        try {
            UserVerification::process($request->input('email'), $token, 'users');
            Flash::success(lang('Email validation successed.'));
        } catch (UserNotFoundException $e) {
            Flash::error(lang('Email not found'));
        } catch (UserIsVerifiedException $e) {
            Flash::success(lang('Email validation successed.'));
        } catch (TokenMismatchException $e) {
            Flash::error(lang('Token mismatch'));
        }

        return redirect('/');
    }

    public function forgetView()
    {
        return view('auth.sendcaptcha');
    }

    public function forget(Request $request)
    {
        $this->validate(
            $request,
            [
                'email' => 'required|email|exists:users,email',
                'captcha' => 'required|captcha',
            ],
            [
                'email.required' => '邮箱地址必须输入!',
                'email.email' => '邮箱地址格式不正确!',
                'email.exists' => '邮箱不存在',
                'captcha.required' => '验证码必须输入',
                'captcha.captcha' => '验证码错误',
            ]
        );
        if (UserCode::isFrequently($request->email)) {
            return redirect(route('auth.forget.view'))->withErrors(['frequently' => '请求太频繁，请一分钟后再请求']);
        }
        $code = UserCode::createCode();
        UserCode::create(
            [
                'email' => $request->email,
                'code' => $code,
                'type' => UserCode::RETRIEVE_PASSWORD,
                'ip' => $request->getClientIp(),
            ]
        );
        \session([self::FIND_PASSWD_EMAIL => $request->email]);
        \session([self::FIND_PASSWD_STEP_ONE => true]);
        dispatch(new SendRetrievePasswordCodeMail($code, $request->email));

        return redirect(route('auth.forget.verify.view'));
    }

    public function forgetVerifyView()
    {
        if (\session(self::FIND_PASSWD_STEP_ONE) !== true) {
            return redirect('/');
        }
        return view('auth.verifycode');
    }

    public function forgetVerify(Request $request)
    {
        if (\session(self::FIND_PASSWD_STEP_ONE) !== true) {
            return redirect('/');
        }

        $this->validate($request, ['code' => 'required'], ['code.required' => '验证码必须传入']);

        /** @var UserCode $userCode */
        $userCode = UserCode::query()
            ->where('email', \session(self::FIND_PASSWD_EMAIL))
            ->where('code', $request->code)
            ->where('is_used', false)
            ->first();

        if (empty($userCode)) {
            return redirect(route('auth.forget.verify.view'))->withErrors(['code' => '无效的验证码']);
        }
        if ($userCode->isExpired()) {
            return redirect(route('auth.forget.verify.view'))->withErrors(['code' => '验证码已过期']);
        }
        if ($userCode->code != $request->code) {
            return redirect(route('auth.forget.verify.view'))->withErrors(['code' => '验证码不正确']);
        }
        $userCode->is_used = true;
        $userCode->save();

        \session([self::FIND_PASSWD_STEP_TWO => true]);

        return redirect(route('auth.reset.password.view'));
    }

    public function resetPasswordView()
    {
        if (\session(self::FIND_PASSWD_STEP_TWO) !== true) {
            return redirect('/');
        }

        return view('auth.resetpassword');
    }

    public function resetPassword(Request $request)
    {
        if (\session(self::FIND_PASSWD_STEP_TWO) !== true) {
            return redirect('/');
        }

        $this->validate(
            $request,
            [
                'password' => 'required|string|between:8,16',
                'verify_password' => 'required'
            ]
        );
        if ($request->password != $request->verify_password) {
            return redirect(route('auth.reset.password'))->withErrors(['password' => '密码不相等']);
        }
        User::query()
            ->where('email', \session(self::FIND_PASSWD_EMAIL))
            ->update(['password' => bcrypt($request->password)]);
        \session([self::FIND_PASSWD_EMAIL => null]);
        \session([self::FIND_PASSWD_STEP_ONE => null]);
        \session([self::FIND_PASSWD_STEP_TWO => null]);

        return redirect('/');
    }
}
